﻿using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Jinndev.UI;
using B83.Win32;
using System.IO;
using Newtonsoft.Json.Linq;
using Jinndev.Json;
using System.Collections;

namespace Jinndev {

    public class CheckCrossRefUI : BaseUIBehaviour {

        #region static
        public static readonly string PATH = "Prefab/UI/CheckCrossRef/CheckCrossRefUI";

        public static CheckCrossRefUI Create() {
            return UIManager.Instance.Add<CheckCrossRefUI>(PATH, UIParam.FullScreen);
        }
        #endregion


        public InputField inputDir;
        public Image progressBar;
        public Text progressText;
        public Text progressInfoText;
        public Button btnStart;
        public RectTransform logArea;

        private LogView logView;

        private void Awake() {
            Util.InitBrowsePasteDirectory(inputDir, "选择项目文件夹");

            inputDir.onValueChanged.AddListener(OnInputChange);

            UnityDragAndDropHook.InstallHook();
            UnityDragAndDropHook.OnDroppedFiles += OnDroppedFiles;

            logView = LogView.Create(logArea);

            progressBar.fillAmount = 0;
            progressText.text = string.Empty;
            progressInfoText.text = string.Empty;

            Refresh();

            //var prefab = ParsePrefab(JArray.Parse(File.ReadAllText(@"E:\Work\JingDong\PlusShop\trunk\program\client\PlusShop\assets\bundle\ui\friend\FriendRoomUI.prefab")));
            //prefab.ForEachComponent((com) => {
            //    Debug.Log(com.type + " : " + com.node.Name);
            //});
            //Debug.Log(prefab.rootNode.Path);
            //foreach (var a in prefab.rootNode.children) {
            //    foreach (var b in a.children) {
            //        foreach (var c in b.children) {
            //            Debug.Log(c.Path);
            //        }
            //    }
            //}

            //Debug.Log(@"E:\Work\JingDong\BigMall\program\client\BigMall\assets\bundle\ui\commonLazy\atlas_1".EndsWith(@"ui\commonLazy\atlas_1"));
        }

        private void OnDestroy() {
            UnityDragAndDropHook.OnDroppedFiles -= OnDroppedFiles;
            UnityDragAndDropHook.UninstallHook();
        }

        private void Update() {
            TryInvokeSingleAction();
        }

        private void OnDroppedFiles(List<string> aPathNames, POINT aDropPoint) {
            foreach (string path in aPathNames) {
                if (Directory.Exists(path)) {
                    inputDir.text = path;
                    return;
                }
            }
            logView.LogError("文件选择错误");
        }

        private void OnInputChange(string value) {
            Refresh();
        }

        private void Refresh() {
            bool enabled = !string.IsNullOrEmpty(inputDir.text) && Directory.Exists(inputDir.text);
            btnStart.interactable = enabled;
        }

        public void OnClickStart() {
            StartCoroutine(Check());
        }

        private IEnumerator Check() {
            logView.Clear();
            btnStart.interactable = false;

            progressBar.fillAmount = 0;
            progressText.text = string.Empty;
            progressInfoText.text = string.Empty;

            string rootPath = inputDir.text;
            int waitFrames = 0;

            // 获取所有资源的uuid所属的bundle路径
            Dictionary<string, ResourceInfo> uuidToPath = new();

            string[] metas = Directory.GetFiles(rootPath, "*.meta", SearchOption.AllDirectories);
            for (int i = 0; i < metas.Length; i++) {
                string metaPath = metas[i];
                string jsonText = File.ReadAllText(metaPath);
                string uuid = CocosUtil.GetResourceUuid(jsonText);

                if (uuid != null && !uuidToPath.ContainsKey(uuid)) {
                    string bundlePath = GetResourceBundlePath(metaPath);
                    if (bundlePath != null) {
                        int priority = GetBundlePriority(bundlePath);
                        string path = metaPath.Substring(0, metaPath.LastIndexOf("."));
                        uuidToPath[uuid] = new ResourceInfo(path, bundlePath, priority);
                    }
                }
                if (waitFrames-- <= 0) {
                    SetProgressLater(i, metas.Length, "搜集meta");
                    yield return new WaitForEndOfFrame();
                    waitFrames = Random.Range(10, 16);
                }
            }
            SetProgressLater(metas.Length - 1, metas.Length, "搜集meta");
            yield return new WaitForEndOfFrame();
            logView.Log("UUID数量: " + uuidToPath.Count);

            waitFrames = 0;
            string[] prefabs = Directory.GetFiles(rootPath, "*.prefab", SearchOption.AllDirectories);
            for (int i = 0; i < prefabs.Length; i++) {
                string prefabFile = prefabs[i];

                string jsonText = File.ReadAllText(prefabFile);
                JArray prefab = JArray.Parse(jsonText);

                //logView.Log($"{Path.GetFileNameWithoutExtension(prefabFile)}子节点数{prefab.Count}");
                CheckSprites(prefabFile, uuidToPath, prefab);
                if (--waitFrames <= 0) {
                    SetProgressLater(i, prefabs.Length, "检查引用");
                    yield return new WaitForEndOfFrame();
                    waitFrames = Random.Range(10, 16);
                }
            }
            SetProgressLater(prefabs.Length - 1, prefabs.Length, "检查引用");
            yield return new WaitForEndOfFrame();
            logView.Log($"完成 - [优先级] 节点路径 => [优先级] 引用资源路径");

            btnStart.interactable = true;
        }

        /// <summary>检查Sprite的引用</summary>
        private void CheckSprites(string prefabFile, Dictionary<string, ResourceInfo> uuidToPath, JArray prefabJson) {
            string projectPath = inputDir.text;

            //string prefabName = Path.GetFileNameWithoutExtension(prefabFile);
            string prefabDir = Path.GetDirectoryName(prefabFile);
            string prefabBundle = GetResourceBundlePath(prefabFile);
            int prefabPriority = prefabBundle == null ? -1 : GetBundlePriority(prefabBundle);

            // 遍历预设中引用的资源
            CocosPrefab prefab = CocosUtil.ParsePrefab(prefabJson, Path.GetFileNameWithoutExtension(prefabFile));
            prefab.ForEachComponent((com) => {
                if (com.HasSprite()) {
                    var refUuids = com.GetSpriteUuids();
                    foreach (var refUuid in refUuids) {
                        if (uuidToPath.TryGetValue(refUuid.Value, out ResourceInfo info)) {
                            string fileDir = info.path;
                            int refPriority = info.priority;

                            if (!fileDir.StartsWith(prefabDir)) {
                                if (prefabPriority != -1 && refPriority != -1 && prefabPriority < refPriority) {
                                    return; // 引用资源的优先级更高
                                }
                                if (prefabBundle == info.bundle) {
                                    return; // 属于同一个bundle
                                }

                                string subDir = fileDir.Substring(projectPath.Length);
                                logView.Log($"[{prefabPriority}] {com.node.Path}.{refUuid.Key} => [{refPriority}] {subDir.Replace("\\", "/")}");
                            }
                        }
                    }
                }
            });
        }

        /// <summary>查找资源所属的bundle</summary>
        private string GetResourceBundlePath(string filePath) {
            DirectoryInfo dirInfo = new FileInfo(filePath).Directory;
            while (true) {
                var metaFile = Path.Combine(dirInfo.Parent.FullName, dirInfo.Name + ".meta");
                if (!File.Exists(metaFile)) {
                    break;
                }
                var jsonText = File.ReadAllText(metaFile);
                JObject meta = JObject.Parse(jsonText);

                JToken isBundle = meta.SelectToken("userData.isBundle");
                if (isBundle != null && isBundle.Value<bool>()) {
                    return dirInfo.FullName;
                }

                dirInfo = dirInfo.Parent;
            }
            return null;
        }

        private int GetBundlePriority(string bundlePath) {
            var metaFile = bundlePath + ".meta";
            var jsonText = File.ReadAllText(metaFile);
            JObject meta = JObject.Parse(jsonText);
            JToken priority = meta.SelectToken("userData.priority");
            return priority == null ? 1 : priority.Value<int>();
        }

        /// <summary>获得其中的Sprite的Uuid</summary>
        private string GetSpriteUuid(JObject node, string type) {
            if (type == "cc.Sprite") {
                string uuid = JsonUtil.GetString(node, "_spriteFrame.__uuid__");
                return CommonUtil.SubStringTo(uuid, "@");
            }
            else if (type == "cc.Button") {
                string uuid = JsonUtil.GetString(node, "_normalSprite.__uuid__");
                return CommonUtil.SubStringTo(uuid, "@");
            }
            return null;
        }

        public struct ResourceInfo {
            public string path;
            public string bundle;
            public int priority;

            public ResourceInfo(string path, string bundle, int priority) {
                this.path = path;
                this.bundle = bundle;
                this.priority = priority;
            }
        }

        private void SetProgressLater(int index, int total, string info) {
            EnqueueAction(() => {
                progressBar.fillAmount = (float)(index + 1) / total;
                progressText.text = (index + 1) + "/" + total;
                progressInfoText.text = info;
            });
        }

    }

}
